package com.lefevre.cms.service.question.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.lefevre.cms.bean.payment.PaymentLog;
import com.lefevre.cms.bean.question.Answer;
import com.lefevre.cms.bean.question.AnswerReply;
import com.lefevre.cms.bean.question.Question;
import com.lefevre.cms.bean.question.QuestionTagAssociation;
import com.lefevre.cms.bean.user.PointLog;
import com.lefevre.cms.mapper.AnswerMapper;
import com.lefevre.cms.mapper.AnswerReplyMapper;
import com.lefevre.cms.mapper.QuestionMapper;
import com.lefevre.cms.mapper.QuestionTagAssociationMapper;
import com.lefevre.cms.service.besa.DaoSupport;
import com.lefevre.cms.service.favorite.FavoriteService;
import com.lefevre.cms.service.message.RemindService;
import com.lefevre.cms.service.question.QuestionService;
import com.lefevre.cms.service.user.UserService;
import com.lefevre.cms.web.action.SystemException;
import com.lefevre.cms.web.action.payment.PaymentManage;
import com.lefevre.cms.web.action.user.PointManage;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 问题管理实现类
 *
 * @author Lefevre
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class QuestionServiceImpl extends DaoSupport<Question> implements QuestionService {

    @Resource
    RemindService remindService;
    @Resource
    FavoriteService favoriteService;
    @Resource
    UserService userService;
    @Resource
    PointManage pointManage;
    @Resource
    PaymentManage paymentManage;
    @Resource
    private QuestionMapper baseMapper;
    @Resource
    private AnswerMapper answerMapper;
    @Resource
    private AnswerReplyMapper answerReplyMapper;
    @Resource
    private QuestionTagAssociationMapper questionTagAssociationMapper;

    /**
     * 根据Id查询问题
     *
     * @param questionId 问题Id
     * @return
     */
    @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)
    public Question findById(Long questionId) {
        return baseMapper.selectById(questionId);
    }

    /**
     * 根据Id集合查询问题
     *
     * @param questionIdList 问题Id集合
     * @return
     */
    @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)
    public List<Question> findByIdList(List<Long> questionIdList) {
        return baseMapper.selectBatchIds(questionIdList);
    }

    /**
     * 根据Id集合查询问题标题
     *
     * @param questionIdList 问题Id集合
     * @return
     */
    @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)
    public List<Question> findTitleByIdList(List<Long> questionIdList) {
        return baseMapper.selectBatchIds(questionIdList);
    }

    /**
     * 根据问题Id集合查询问题
     *
     * @param questionIdList 话题Id集合
     * @return
     */
    @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)
    public List<Question> findQuestionByQuestionIdList(List<Long> questionIdList) {
        return baseMapper.selectBatchIds(questionIdList);
    }

    /**
     * 分页查询问题内容
     *
     * @param firstIndex
     * @param maxResult
     * @param userName   用户名称
     * @param isStaff    是否为员工
     * @return
     */
    @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)
    public List<Question> findQuestionContentByPage(int firstIndex, int maxResult, String userName, boolean isStaff) {
        LambdaQueryWrapper<Question> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Question::getUserName, userName);
        wrapper.eq(Question::getIsStaff, isStaff);
        Page<Question> questionPage = baseMapper.selectPage(new Page<>(firstIndex, maxResult), wrapper);

        return questionPage.getRecords();
    }

    /**
     * 分页查询问题
     *
     * @param firstIndex 开始索引
     * @param maxResult  需要获取的记录数
     * @return
     */
    @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)
    public List<Question> findQuestionByPage(int firstIndex, int maxResult) {
        Page<Question> questionPage = baseMapper.selectPage(new Page<>(firstIndex, maxResult), null);
        return questionPage.getRecords();
    }

    /**
     * 根据问题Id查询问题标签关联
     *
     * @param questionId 问题Id
     * @return
     */
    @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)
    public List<QuestionTagAssociation> findQuestionTagAssociationByQuestionId(Long questionId) {
        return questionTagAssociationMapper.selectList(new LambdaQueryWrapper<QuestionTagAssociation>()
                .eq(QuestionTagAssociation::getQuestionId, questionId));
    }


    /**
     * 保存问题
     *
     * @param question                   问题
     * @param questionTagAssociationList 问题标签关联集合
     * @param point                      扣减用户积分
     * @param pointLog                   积分日志
     * @param amount                     扣减用户预存款
     * @param paymentLog                 支付日志
     */
    public void saveQuestion(Question question, List<QuestionTagAssociation> questionTagAssociationList, Long point, PointLog pointLog, BigDecimal amount, PaymentLog paymentLog) {

        baseMapper.insert(question);

        for (QuestionTagAssociation questionTagAssociation : questionTagAssociationList) {
            questionTagAssociation.setQuestionId(question.getId());
            questionTagAssociationMapper.insert(questionTagAssociation);
        }
        if (point != null && point > 0L) {//积分
            pointLog.setParameterId(question.getId());
            Object pointLogObject = pointManage.createPointLogObject(pointLog);
            //扣减用户积分
            int i = userService.subtractUserPoint(question.getUserName(), point, pointLogObject);
            if (i == 0) {
                throw new SystemException("扣减积分失败");
            }
        }
        if (amount != null && amount.compareTo(new BigDecimal("0")) > 0) {//余额
            paymentLog.setSourceParameterId(String.valueOf(question.getId()));
            Object paymentLogObject = paymentManage.createPaymentLogObject(paymentLog);
            //扣减用户预存款
            int i = userService.subtractUserDeposit(question.getUserName(), amount, paymentLogObject);
            if (i == 0) {
                throw new SystemException("扣减预存款失败");
            }
        }
    }


    /**
     * 保存追加问题
     *
     * @param questionId    问题Id
     * @param appendContent 追加问题内容 AppendQuestionItem对象的JSON格式加上逗号
     * @return
     */
    public Integer saveAppendQuestion(Long questionId, String appendContent) {
        return baseMapper.appendContent(questionId, appendContent);
    }

    /**
     * 修改追加问题
     *
     * @param questionId    问题Id
     * @param appendContent 追加问题内容
     * @return
     */
    public Integer updateAppendQuestion(Long questionId, String appendContent) {
        return baseMapper.update(null, new LambdaUpdateWrapper<Question>()
                .set(Question::getAppendContent, appendContent)
                .eq(Question::getId, questionId));
    }


    /**
     * 增加展示次数
     *
     * @param countMap key: 话题Id value:展示次数
     * @return
     */
    public int addViewCount(Map<Long, Long> countMap) {
        int i = 0;
        for (Map.Entry<Long, Long> entry : countMap.entrySet()) {
            Question question = baseMapper.selectById(entry.getKey());
            question.setViewTotal(question.getViewTotal() + entry.getValue());

            i += baseMapper.updateById(question);
        }
        return i;
    }

    /**
     * 修改采纳答案Id
     *
     * @param questionId 问题Id
     * @param answerId   答案Id
     * @return
     */
    public int updateAdoptionAnswerId(Long questionId, Long answerId) {
        return baseMapper.update(null, new LambdaUpdateWrapper<Question>()
                .set(Question::getAdoptionAnswerId, answerId)
                .eq(Question::getId, questionId));
    }

    /**
     * 修改问题
     *
     * @param question                   问题
     * @param questionTagAssociationList 问题标签关联集合
     * @param changePointSymbol          变更积分符号 true：问题增加积分  false：问题减少积分
     * @param changePoint                变更积分
     * @param changeAmountSymbol         变更金额符号 true：问题增加金额  false：问题减少金额
     * @param changeAmount               变更金额
     * @param pointLogObject             用户悬赏积分日志
     * @param paymentLogObject           用户悬赏金额日志
     * @return
     */
    public Integer updateQuestion(Question question, List<QuestionTagAssociation> questionTagAssociationList,
                                  boolean changePointSymbol, Long changePoint, boolean changeAmountSymbol,
                                  BigDecimal changeAmount, Object pointLogObject, Object paymentLogObject) {

        int i = baseMapper.updateById(question);
        if (i > 0) {
            //先删除
            questionTagAssociationMapper.delete(new LambdaUpdateWrapper<QuestionTagAssociation>()
                    .eq(QuestionTagAssociation::getQuestionId, question.getId()));

            //保存
            for (QuestionTagAssociation questionTagAssociation : questionTagAssociationList) {
                questionTagAssociation.setQuestionId(question.getId());
                questionTagAssociationMapper.insert(questionTagAssociation);
            }

            if (pointLogObject != null) {
                if (changePointSymbol) {
                    //扣减用户积分
                    int j = userService.subtractUserPoint(question.getUserName(), changePoint, pointLogObject);
                    if (j == 0) {
                        throw new SystemException("扣减积分失败");
                    }
                } else {
                    //增加用户积分
                    userService.addUserPoint(question.getUserName(), changePoint, pointLogObject);
                }
            }
            if (paymentLogObject != null) {
                if (changeAmountSymbol) {//增加
                    //扣减用户预存款
                    int j = userService.subtractUserDeposit(question.getUserName(), changeAmount, paymentLogObject);
                    if (j == 0) {
                        throw new SystemException("扣减预存款失败");
                    }
                } else {
                    //增加用户预存款
                    userService.addUserDeposit(question.getUserName(), changeAmount, paymentLogObject);
                }
            }
        }
        return i;
    }

    /**
     * 修改问题最后回答时间
     *
     * @param questionId     问题Id
     * @param lastAnswerTime 最后回答时间
     * @return
     */
    public Integer updateQuestionAnswerTime(Long questionId, Date lastAnswerTime) {
        return baseMapper.update(null, new LambdaUpdateWrapper<Question>()
                .set(Question::getLastAnswerTime, lastAnswerTime)
                .eq(Question::getId, questionId));
    }

    /**
     * 修改问题状态
     *
     * @param questionId 问题Id
     * @param status     状态
     * @return
     */
    public int updateQuestionStatus(Long questionId, Integer status) {
        return baseMapper.update(null, new LambdaUpdateWrapper<Question>()
                .set(Question::getStatus, status)
                .eq(Question::getId, questionId));
    }

    /**
     * 修改问题标签Id
     *
     * @param old_tagId 旧标签Id
     * @param new_tagId 新标签Id
     * @return
     */
    public Integer updateTagId(Long old_tagId, Long new_tagId) {
        return questionTagAssociationMapper.update(null, new LambdaUpdateWrapper<QuestionTagAssociation>()
                .set(QuestionTagAssociation::getQuestionTagId, new_tagId)
                .eq(QuestionTagAssociation::getQuestionTagId, old_tagId));
    }

    /**
     * 根据标签Id删除问题标签关联
     *
     * @param questionTagId 问题标签Id
     * @return
     */
    public Integer deleteQuestionTagAssociation(Long questionTagId) {
        return questionTagAssociationMapper.delete(new LambdaUpdateWrapper<QuestionTagAssociation>()
                .eq(QuestionTagAssociation::getQuestionTagId, questionTagId));
    }

    /**
     * 根据用户名称集合删除问题标签关联
     *
     * @param userNameList 用户名称集合
     * @return
     */
    public Integer deleteQuestionTagAssociationByUserId(List<String> userNameList) {
        return questionTagAssociationMapper.delete(new LambdaUpdateWrapper<QuestionTagAssociation>()
                .in(QuestionTagAssociation::getUserName, userNameList));
    }


    /**
     * 还原问题
     *
     * @param questionList 问题集合
     * @return
     */
    public Integer reductionQuestion(List<Question> questionList) {
        int i = 0;
        if (questionList != null && questionList.size() > 0) {
            for (Question question : questionList) {
                if (question.getStatus() > 100) {
                    question.setStatus(question.getStatus() - 100);
                    i += baseMapper.updateById(question);
                }
            }
        }
        return i;
    }

    /**
     * 标记删除问题
     *
     * @param questionId 问题Id
     * @return
     */
    public Integer markDelete(Long questionId) {
        Question question = baseMapper.selectById(questionId);
        question.setStatus(question.getStatus() + 100);

        return baseMapper.updateById(question);
    }

    /**
     * 删除问题
     *
     * @param questionId       问题Id
     * @param userName         用户名称
     * @param point            扣减用户积分
     * @param pointLogObject   积分日志
     * @param amount           扣减用户预存款
     * @param paymentLogObject 支付日志
     * @return
     */
    public Integer deleteQuestion(Long questionId, String userName, Long point, Object pointLogObject, BigDecimal amount, Object paymentLogObject) {
        int i = baseMapper.deleteById(questionId);

        //删除答案
        answerMapper.delete(new LambdaUpdateWrapper<Answer>().eq(Answer::getQuestionId, questionId));

        //删除答案回复
        answerReplyMapper.delete(new LambdaUpdateWrapper<AnswerReply>().eq(AnswerReply::getQuestionId, questionId));

        //删除提醒
        remindService.deleteRemindByQuestionId(questionId);

        //删除收藏
        favoriteService.deleteFavoriteByQuestionId(questionId);

        if (point != null && point > 0L) {//积分
            //增加用户积分
            userService.addUserPoint(userName, point, pointLogObject);
        }
        if (amount != null && amount.compareTo(new BigDecimal("0")) > 0) {//余额
            //增加用户预存款
            userService.addUserDeposit(userName, amount, paymentLogObject);
        }
        return i;
    }

    /**
     * 根据用户名称集合删除问题
     *
     * @param userNameList 用户名称集合
     * @return
     */
    public Integer deleteQuestion(List<String> userNameList) {
        return baseMapper.delete(new LambdaUpdateWrapper<Question>()
                .in(Question::getUserName, userNameList)
                .eq(Question::getIsStaff, false));
    }


    /**
     * 增加总答案数
     *
     * @param questionId 问题Id
     * @param quantity   数量
     * @return
     */
    public int addAnswerTotal(Long questionId, Long quantity) {
        Question question = baseMapper.selectById(questionId);
        question.setAnswerTotal(question.getAnswerTotal() + quantity);
        return baseMapper.updateById(question);
    }

    /**
     * 减少总答案数
     *
     * @param questionId 问题Id
     * @param quantity   数量
     * @return
     */
    public int subtractAnswerTotal(Long questionId, Long quantity) {
        Question question = baseMapper.selectById(questionId);
        question.setAnswerTotal(question.getAnswerTotal() - quantity);
        return baseMapper.updateById(question);
    }

    /**
     * 查询待审核问题数量
     *
     * @return
     */
    @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)
    public Long auditQuestionCount() {
        return baseMapper.selectCount(new LambdaQueryWrapper<Question>().eq(Question::getStatus, 10));
    }
}
